package com.ls.pattern.interpreter.util;

import com.ls.pattern.interpreter.*;
import com.ls.pattern.interpreter.constants.SymbolEnum;

import java.util.EnumSet;
import java.util.Optional;
import java.util.Stack;


/**
 * 操作工具类
 *
 * @author 挥之以墨
 */
public class OperateUtils {

    /**
     * 判断是否为运算符
     */
    public static boolean isSymbol(String symbol) {
        return EnumSet.allOf(SymbolEnum.class).contains(SymbolEnum.getBySymbol(symbol));
    }

    /**
     * 获取计算结果解释器
     *
     * @param left   符号左边的数字
     * @param right  符号右边的数字
     * @param symbol 运算符号
     * @return 计算结果解释器
     */
    public static BaseInterpreter getInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right, String symbol) {
        return Optional.ofNullable(SymbolEnum.getBySymbol(symbol))
                .map(symbolEnum -> {
                    switch (symbolEnum) {
                        case ADD:
                            return new AddInterpreter(left, right);
                        case SUB:
                            return new SubInterpreter(left, right);
                        case MUL:
                            return new MulInterpreter(left, right);
                        case DIV:
                            return new DivInterpreter(left, right);
                        default:
                            return null;
                    }
                }).orElse(null);
    }

    /**
     * 与符号栈顶比较运算符优先级
     * 优先级从高到低为：第一级( ，第二级 * / ，第三层级 + - ，第四层级 )
     *
     * @param symbol      运算符
     * @param symbolStack 运算符栈
     * @return 1.空栈返回true 2.左括号返回true 3.传入符号优先于栈顶符号则返回true。
     */
    public static boolean comparePri(String symbol, Stack<String> symbolStack) {
        if (symbolStack.empty()) {
            return true;
        }

        // 查看栈顶符号，而非弹出
        String top = symbolStack.peek();
        if (SymbolEnum.LEFT_BRACKET.getSymbol().equals(top)) {
            return true;
        }
        // 比较优先级，乘除法只和加减法做对比
        return Optional.ofNullable(SymbolEnum.getBySymbol(symbol))
                .map(symbolEnum -> {
                    switch (symbolEnum) {
                        case LEFT_BRACKET:
                            return true;
                        case MUL:
                        case DIV:
                            return SymbolEnum.ADD.getSymbol().equals(top) || SymbolEnum.SUB.getSymbol().equals(top);
                        case ADD:
                        case SUB:
                        case RIGHT_BRACKET:
                            return false;
                        default:
                            break;
                    }
                    return true;
                }).orElse(true);

    }

}
